/*
 * EventLoop.h
 *
 *	Author: stravant
 *	Description:
 *	   Classes:	EventLoop
 *				Task
 *				Task
 */

#ifndef EVENTLOOP_H_
#define EVENTLOOP_H_

#include "boost/thread/exceptions.hpp"
#include "boost/thread/mutex.hpp"
#include "boost/thread/recursive_mutex.hpp"

#include <iostream>
#include <queue>
#include <list>

#include "../core/Include.h"
#include "../core/ThreadLocalPtr.h"
#include "../core/Time.h"
#include "../core/WeakRef.h"
#include "../core/Action.h"
#include "../core/WorkQueue.h"

namespace tbt {

/*
 * class Task
 *  Represents one peristent task in an event loop. Tasks are the means of executing
 *  Actions, rather than actions being directly executed from an event loop.
 *  Tasks are owned by the event loop they are added to.
 */
class Task {
public:
	Task() {}
	virtual ~Task() {}
	virtual bool tick(Time t) = 0;
};


/*
 * class EventLoop
 *  Only one event loop may be created per Thread. An event loop is attached to
 *  the thread which it is created on, and detached on destruction.
 *
 *  EventLoops are thread-safe for Tasks and actions, they may be added from a
 *  thread other than the owning thread safely.
 */
class EventLoop: public RefCounted<EventLoop> {
public:
	class DestructionListener {
	public:
		DestructionListener() {}
		virtual ~DestructionListener() {}
		virtual void onEventLoopDestroyed() = 0;
	};

public:
	EventLoop();
	~EventLoop();

	//run the event loop
	void run();

	//is running
	bool isRunning() const;

	//stop the event loop as soon as possible
	void stopSoon();

	//add a destruction listener, destruction listeners are not owned
	//by the event loop, and must free themselves.
	void addDestructionListener(DestructionListener* o);
	void removeDestructionListener(DestructionListener* o);

	//queue an action. The event loop will take ownership of the action
	//and delete it once executed.
	void queueAction(Action* task);
	void queueActionDelayed(Action* task, TimeDelta delay);

	//add a task. The event loop will take ownership of the task, and
	//delete it once it's tick function returns true
	void addTask(Task* task);

	//get the current thread's event-loop
	static Ref<EventLoop> current() {
		return mCurrentEventLoop.get();
	}
private:
	struct DelayedAction {
		DelayedAction(Action* action, Time timeToRun):
			ActionToRun(action), TimeToRun(timeToRun) {
		}
		~DelayedAction() {
			delete ActionToRun;
		}
		Action* ActionToRun;
		Time TimeToRun;
		//
		void run() {
			ActionToRun->run();
		}
	};
	struct DelayedActionCompare {
		bool operator()(DelayedAction* a, DelayedAction* b) const {
			return a->TimeToRun > b->TimeToRun;
		}
	};

private:
	bool updateTasks();
	bool updateActions();
	bool updateDelayedActions();

private:
	//Action container
	boost::mutex mActionWriteLock;
	std::vector<Action*> mActionAdd; //added but not yet added to queue
	std::queue<Action*> mActionQueue;

	//DelayedAction container
	boost::mutex mDelayedActionWriteLock;
	std::vector<DelayedAction*> mDelayedActionAdd;
	std::priority_queue<DelayedAction*,
		std::vector<DelayedAction*>, DelayedActionCompare> mDelayedActionQueue;

	//boost::mutex mDestructionListenerWriteLock;
	//std::vector<DestructionListener*> mDestructionListenerAdd;
	//std::vector<DestructionListener*> mDestructionListenerRemove;
	std::list<DestructionListener*> mDestructionListeners;

	boost::mutex mTaskListWriteLock;
	std::vector<Task*> mTaskAdd;
	std::list<Task*> mTaskList;

	bool mInDestructor;

	bool mIsRunning;
	bool mStopRequested;

	static ThreadLocalPtr<EventLoop> mCurrentEventLoop;
};


/*
 * class StopAction
 *  Convinience Action for stopping an event loop
 */
class StopAction: public Action {
public:
	StopAction(Ref<EventLoop> e): mObj(e) {}
	virtual void run() {mObj->stopSoon(); }
private:
	Ref<EventLoop> mObj;
};

}

#endif /* EVENTLOOP_H_ */













